/**
 * 数据库初始化脚本
 * 使用方法: 
 *   npm run init-db        - 正常初始化（如果表已存在则跳过）
 *   npm run init-db:force  - 强制初始化（删除所有表后重新创建）
 */

import mysql from 'mysql2/promise';
import fs from 'fs';
import path from 'path';
import dotenv from 'dotenv';
import { hashPassword } from '../src/utils/password';
import { utils } from '../src/utils/utils';

// 加载环境配置
const env = process.env.NODE_ENV || 'dev';
const envFile = env === 'prd' ? '.env.prd' : '.env.dev';
dotenv.config({ path: path.resolve(process.cwd(), envFile) });
dotenv.config();

const config = {
  host: process.env.MYSQL_HOST || 'localhost',
  port: parseInt(process.env.MYSQL_PORT || '3306', 10),
  user: process.env.MYSQL_USER || 'root',
  password: process.env.MYSQL_PASSWORD || '',
  database: process.env.MYSQL_DATABASE || 'member_management',
};

const isForce = process.argv.includes('--force') || process.argv.includes('-f');

/**
 * 同步表结构：检查 schema.sql 中定义的表结构，如果实际数据库中的表缺少字段或索引，则添加
 */
async function syncTableStructure(connection: mysql.Connection, database: string): Promise<void> {
  try {
    const sqlPath = path.join(__dirname, '../src/database/schema.sql');
    if (!fs.existsSync(sqlPath)) {
      return;
    }

    const sqlContent = fs.readFileSync(sqlPath, 'utf-8');
    
    // 解析 schema.sql 中的表结构
    const tableDefinitions = new Map<string, { columns: Map<string, string>, indexes: Map<string, string> }>();
    
    // 匹配 CREATE TABLE 语句（使用非贪婪匹配，直到遇到 ENGINE 或分号）
    const createTableRegex = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"]?(\w+)[`"]?\s*\(([\s\S]*?)\)\s*(?:ENGINE|;)/gi;
    let match;
    
    while ((match = createTableRegex.exec(sqlContent)) !== null) {
      const tableName = match[1];
      const tableBody = match[2];
      
      const columns = new Map<string, string>();
      const indexes = new Map<string, string>();
      
      // 解析表体：按行分割，处理列定义和索引
      const lines = tableBody.split('\n');
      let currentLine = '';
      
      for (const line of lines) {
        const trimmed = line.trim();
        if (!trimmed) continue;
        
        // 累积多行定义（直到遇到逗号或结束）
        currentLine += (currentLine ? ' ' : '') + trimmed;
        
        // 如果当前行以逗号结尾或者是最后一行，处理它
        if (currentLine.endsWith(',') || trimmed.endsWith(')')) {
          currentLine = currentLine.replace(/,\s*$/, '').trim();
          
          // 处理索引定义
          if (currentLine.match(/^(PRIMARY\s+KEY|UNIQUE\s+KEY|KEY|INDEX)/i)) {
            const keyMatch = currentLine.match(/(?:UNIQUE\s+)?KEY\s+[`"]?(\w+)[`"]?\s*\(([^)]+)\)/i);
            if (keyMatch) {
              indexes.set(keyMatch[1], currentLine);
            }
          } else {
            // 处理列定义：格式为 `column_name` type constraints
            const colMatch = currentLine.match(/^[`"]?(\w+)[`"]?\s+(.+)$/);
            if (colMatch) {
              const colName = colMatch[1];
              const colDef = colMatch[2].trim();
              // 移除可能的尾随逗号
              columns.set(colName, colDef.replace(/,\s*$/, ''));
            }
          }
          
          currentLine = '';
        }
      }
      
      // 处理最后一行（如果没有逗号）
      if (currentLine) {
        const colMatch = currentLine.match(/^[`"]?(\w+)[`"]?\s+(.+)$/);
        if (colMatch) {
          const colName = colMatch[1];
          const colDef = colMatch[2].trim();
          columns.set(colName, colDef);
        }
      }
      
      tableDefinitions.set(tableName, { columns, indexes });
    }
    
    // 检查每个表，如果缺少字段则添加
    for (const [tableName, definition] of tableDefinitions.entries()) {
      // 检查表是否存在
      const [tableExists] = await connection.query<any[]>(
        `SELECT COUNT(*) as count FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?`,
        [database, tableName]
      );
      
      if (tableExists[0].count === 0) {
        continue; // 表不存在，跳过（会在创建表时处理）
      }
      
      // 获取实际表的列信息
      const [actualColumns] = await connection.query<any[]>(
        `SELECT COLUMN_NAME FROM information_schema.COLUMNS 
         WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
         ORDER BY ORDINAL_POSITION`,
        [database, tableName]
      );
      
      const actualColumnNames = new Set(actualColumns.map((col: any) => col.COLUMN_NAME));
      
      // 检查缺失的列
      for (const [colName, colDef] of definition.columns.entries()) {
        if (!actualColumnNames.has(colName)) {
          // 构建 ALTER TABLE 语句
          // 如果目标定义是 NOT NULL 且没有默认值，则先以 DEFAULT NULL 形式添加，避免对已有数据报错
          let adjustedDef = colDef;
          const hasNotNull = /\bNOT\s+NULL\b/i.test(adjustedDef);
          const hasDefault = /\bDEFAULT\b/i.test(adjustedDef);
          if (hasNotNull && !hasDefault) {
            adjustedDef = adjustedDef.replace(/\bNOT\s+NULL\b/gi, 'DEFAULT NULL');
          }
          const alterSql = `ALTER TABLE \`${tableName}\` ADD COLUMN \`${colName}\` ${adjustedDef}`;
          try {
            await connection.query(alterSql);
            console.log(`  ✓ 添加字段: ${tableName}.${colName}`);
          } catch (err: any) {
            console.log(`  ⚠️  添加字段失败 ${tableName}.${colName}: ${err.message}`);
          }
        }
      }
      
      // 获取实际表的索引信息
      const [actualIndexes] = await connection.query<any[]>(
        `SELECT DISTINCT INDEX_NAME FROM information_schema.STATISTICS 
         WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND INDEX_NAME != 'PRIMARY'`,
        [database, tableName]
      );
      
      const actualIndexNames = new Set(actualIndexes.map((idx: any) => idx.INDEX_NAME));
      
      // 检查缺失的索引
      for (const [idxName, idxDef] of definition.indexes.entries()) {
        if (!actualIndexNames.has(idxName)) {
          // 提取索引列定义
          const idxColMatch = idxDef.match(/\(([^)]+)\)/);
          if (idxColMatch) {
            const idxColumns = idxColMatch[1];
            // 构建 ALTER TABLE 语句
            let alterSql = `ALTER TABLE \`${tableName}\` ADD `;
            if (idxDef.includes('UNIQUE KEY') || idxDef.includes('UNIQUE')) {
              alterSql += `UNIQUE KEY \`${idxName}\` (${idxColumns})`;
            } else {
              alterSql += `KEY \`${idxName}\` (${idxColumns})`;
            }
            try {
              await connection.query(alterSql);
              console.log(`  ✓ 添加索引: ${tableName}.${idxName}`);
            } catch (err: any) {
              console.log(`  ⚠️  添加索引失败 ${tableName}.${idxName}: ${err.message}`);
            }
          }
        }
      }
    }
  } catch (error: any) {
    console.error('  ⚠️  同步表结构失败:', error.message);
    // 不抛出错误，因为这不是关键操作
  }
}

/**
 * 从数据库导出表结构并保存到 schema_online.sql 文件
 * 注意：schema.sql 是源文件，不会被覆盖；schema_online.sql 记录实际数据库结构
 */
async function exportSchemaToFile(connection: mysql.Connection, database: string): Promise<void> {
  try {
    // 确保导出前已同步结构，避免把缺失列的旧结构导出
    await syncTableStructure(connection, database);
    console.log('\n正在导出数据库结构到 schema_online.sql...');
    
    // 获取所有表名
    const [tables] = await connection.query<any[]>(
      `SELECT TABLE_NAME, TABLE_COMMENT 
       FROM information_schema.TABLES 
       WHERE TABLE_SCHEMA = ? 
       ORDER BY TABLE_NAME`,
      [database]
    );

    if (tables.length === 0) {
      console.log('  - 没有找到表');
      return;
    }

    const schemaPath = path.join(__dirname, '../src/database/schema_online.sql');
    let schemaContent = '-- 会员管理系统数据库表结构（在线数据库实际结构）\n';
    schemaContent += '-- 此文件由数据库初始化脚本自动生成，记录实际数据库的结构\n';
    schemaContent += '-- 注意：schema.sql 是源文件，不会被覆盖；此文件仅用于参考\n\n';

    for (const table of tables) {
      const tableName = table.TABLE_NAME;
      const tableComment = table.TABLE_COMMENT || '';

      // 获取表的创建语句
      const [createTableResult] = await connection.query<any[]>(
        `SHOW CREATE TABLE \`${tableName}\``
      );

      if (createTableResult.length === 0) {
        continue;
      }

      let createStatement = createTableResult[0]['Create Table'];

      // 格式化 CREATE TABLE 语句
      // 将 CREATE TABLE 转换为 CREATE TABLE IF NOT EXISTS
      createStatement = createStatement.replace(/^CREATE TABLE/, 'CREATE TABLE IF NOT EXISTS');

      // 添加表注释（如果表名有注释，使用表注释；否则使用表名）
      if (tableComment) {
        schemaContent += `-- ${tableComment}\n`;
      } else {
        // 从表名生成注释（将下划线转换为空格，首字母大写）
        const comment = tableName
          .split('_')
          .map((word: string) => word.charAt(0).toUpperCase() + word.slice(1))
          .join(' ');
        schemaContent += `-- ${comment}\n`;
      }
      
      schemaContent += `${createStatement};\n\n`;
    }

    // 写入 schema_online.sql（记录实际数据库结构，不覆盖源文件 schema.sql）
    fs.writeFileSync(schemaPath, schemaContent, 'utf-8');
    console.log(`  ✓ 已导出 schema_online.sql 文件 (${tables.length} 个表)`);
  } catch (error: any) {
    console.error('  ⚠️  导出 schema_online.sql 失败:', error.message);
    // 不抛出错误，因为这不是关键操作
  }
}

async function initDatabase() {
  let connection: mysql.Connection | null = null;

  try {
    console.log('开始初始化数据库...');
    console.log(`环境: ${env}`);
    console.log(`数据库: ${config.database}`);
    console.log(`模式: ${isForce ? '强制初始化（将删除所有表）' : '正常初始化'}`);

    // 连接数据库（不指定数据库，先创建数据库）
    connection = await mysql.createConnection({
      host: config.host,
      port: config.port,
      user: config.user,
      password: config.password,
    });

    // 创建数据库（如果不存在）
    await connection.query(`CREATE DATABASE IF NOT EXISTS \`${config.database}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`);
    console.log(`✓ 数据库 ${config.database} 已准备就绪`);

    // 切换到目标数据库
    await connection.query(`USE \`${config.database}\``);

    // 如果是强制模式，删除所有表
    if (isForce) {
      console.log('正在删除现有表...');
      const [tables] = await connection.query<any[]>(
        `SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?`,
        [config.database]
      );

      if (tables.length > 0) {
        // 禁用外键检查
        await connection.query('SET FOREIGN_KEY_CHECKS = 0');
        
        for (const table of tables) {
          await connection.query(`DROP TABLE IF EXISTS \`${table.TABLE_NAME}\``);
          console.log(`  - 删除表: ${table.TABLE_NAME}`);
        }
        
        // 启用外键检查
        await connection.query('SET FOREIGN_KEY_CHECKS = 1');
        console.log('✓ 所有表已删除');
      } else {
        console.log('✓ 没有需要删除的表');
      }
    }

    // 读取并执行SQL文件
    const sqlPath = path.join(__dirname, '../src/database/schema.sql');
    if (!fs.existsSync(sqlPath)) {
      throw new Error(`SQL文件不存在: ${sqlPath}`);
    }

    const sqlContent = fs.readFileSync(sqlPath, 'utf-8');
    
    // 移除注释行和空行，然后按分号分割SQL语句
    const statements = sqlContent
      .split('\n')
      .map(line => {
        // 移除行内注释
        const commentIndex = line.indexOf('--');
        if (commentIndex >= 0) {
          return line.substring(0, commentIndex).trim();
        }
        return line.trim();
      })
      .filter(line => line.length > 0)
      .join('\n')
      .split(';')
      .map(s => s.trim())
      .filter(s => s.length > 0 && !s.startsWith('--'));

    console.log('正在创建表结构...');
    for (const statement of statements) {
      if (statement.trim()) {
        try {
          await connection.query(statement);
          // 提取表名（匹配 CREATE TABLE IF NOT EXISTS `table_name` 或 CREATE TABLE `table_name`）
          const tableMatch = statement.match(/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"]?(\w+)[`"]?/i);
          if (tableMatch) {
            console.log(`  ✓ 创建表: ${tableMatch[1]}`);
          }
        } catch (err: any) {
          // 如果是"表已存在"错误且不是强制模式，则跳过
          if (!isForce && err.code === 'ER_TABLE_EXISTS_ERROR') {
            const tableMatch = statement.match(/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"]?(\w+)[`"]?/i);
            const tableName = tableMatch ? tableMatch[1] : 'unknown';
            console.log(`  - 表已存在，跳过: ${tableName}`);
          } else {
            console.error(`执行SQL失败: ${statement.substring(0, 100)}...`);
            throw err;
          }
        }
      }
    }

    console.log('✓ 表结构创建完成');

    // 同步表结构（检查并添加缺失的字段和索引）
    console.log('正在同步表结构...');
    await syncTableStructure(connection, config.database);
    console.log('✓ 表结构同步完成');

    // 创建默认权限：系统管理员
    console.log('正在创建默认权限...');
    const adminPermissionName = '系统管理员';
    const adminPermissionCode = 'SYSTEM_ADMIN';

    // 检查权限是否已存在
    const [existingPermissions] = await connection.query<any[]>(
      'SELECT * FROM permissions WHERE code = ?',
      [adminPermissionCode]
    );

    let permissionId: string;
    if (existingPermissions.length > 0) {
      permissionId = existingPermissions[0].id;
      if (isForce) {
        // 强制模式：更新权限信息
        await connection.query(
          'UPDATE permissions SET name = ?, description = ? WHERE code = ?',
          [adminPermissionName, '系统管理员权限，不可删除', adminPermissionCode]
        );
        console.log(`  - 更新已存在的权限: ${adminPermissionName}`);
      } else {
        console.log(`  - 权限 ${adminPermissionName} 已存在，跳过创建`);
        permissionId = existingPermissions[0].id;
      }
    } else {
      // 创建默认权限
      permissionId = utils.generateUUID();
      await connection.query(
        `INSERT INTO permissions (id, name, code, description)
         VALUES (?, ?, ?, ?)`,
        [permissionId, adminPermissionName, adminPermissionCode, '系统管理员权限，不可删除']
      );
      console.log(`  ✓ 创建默认权限成功: ${adminPermissionName}`);
    }

    // 创建默认管理员用户
    console.log('正在创建默认管理员用户...');
    const adminUsername = 'admin';
    const adminPassword = 'Admin123';

    // 检查用户是否已存在
    const [existingUsers] = await connection.query<any[]>(
      'SELECT * FROM users WHERE username = ?',
      [adminUsername]
    );

    let userId: string;
    if (existingUsers.length > 0) {
      userId = existingUsers[0].id;
      if (isForce) {
        // 强制模式：更新用户信息（不删除，只更新）
        const hashedPassword = await hashPassword(adminPassword);
        await connection.query(
          'UPDATE users SET password = ?, nickname = ?, is_admin = 1, status = 1 WHERE username = ?',
          [hashedPassword, '管理员', adminUsername]
        );
        console.log(`  - 更新已存在的用户: ${adminUsername}`);
      } else {
        console.log(`  - 用户 ${adminUsername} 已存在，跳过创建`);
      }
    } else {
      // 创建管理员用户
      userId = utils.generateUUID();
      const hashedPassword = await hashPassword(adminPassword);

      await connection.query(
        `INSERT INTO users (id, username, password, nickname, is_admin, status)
         VALUES (?, ?, ?, ?, 1, 1)`,
        [userId, adminUsername, hashedPassword, '管理员']
      );
      console.log(`  ✓ 创建管理员用户成功`);
    }

    // 关联用户和权限
    console.log('正在关联用户和权限...');
    const [existingRelations] = await connection.query<any[]>(
      'SELECT * FROM user_permissions WHERE user_id = ? AND permission_id = ?',
      [userId, permissionId]
    );

    if (existingRelations.length === 0) {
      const relationId = utils.generateUUID();
      await connection.query(
        'INSERT INTO user_permissions (id, user_id, permission_id) VALUES (?, ?, ?)',
        [relationId, userId, permissionId]
      );
      console.log(`  ✓ 关联用户和权限成功`);
    } else {
      console.log(`  - 用户和权限已关联，跳过`);
    }

    console.log(`    用户名: ${adminUsername}`);
    console.log(`    密码: ${adminPassword}`);
    console.log(`    用户ID: ${userId}`);
    console.log(`    权限: ${adminPermissionName} (${adminPermissionCode})`);

    console.log('\n数据库初始化完成！');
    console.log('\n默认管理员账号：');
    console.log(`  用户名: ${adminUsername}`);
    console.log(`  密码: ${adminPassword}`);
    console.log(`  权限: ${adminPermissionName}`);
    console.log('\n⚠️  重要提示：');
    console.log(`  - ${adminUsername} 用户不可删除`);
    console.log(`  - ${adminPermissionName} 权限不可删除`);
    console.log('\n请妥善保管管理员账号信息，首次登录后建议修改密码！');

    // 导出数据库结构到 schema.sql
    await exportSchemaToFile(connection, config.database);

    await connection.end();
  } catch (error: any) {
    console.error('\n❌ 数据库初始化失败:');
    console.error(error.message);
    if (connection) {
      await connection.end();
    }
    process.exit(1);
  }
}

initDatabase();

